require('v8-compile-cache');
const MiniCssExtractPlugin = require('mini-css-extract-plugin');
const TerserPlugin = require('terser-webpack-plugin');
const { CleanWebpackPlugin } = require('clean-webpack-plugin');
const { BundleAnalyzerPlugin } = require('webpack-bundle-analyzer');
const { WebpackManifestPlugin } = require('webpack-manifest-plugin');
const FileManagerPlugin = require('filemanager-webpack-plugin');
// var LodashModuleReplacementPlugin = require('lodash-webpack-plugin');
const DynamicPublicPathPlugin = require('./dynamic-publicpath-plugin');

const {
  name,
  resolve,
  plugins,
  externals,
  getWebpackOverridesConfig,
  isSpecialApp,
} = require('./utils');
const { resolveApp, resolveSeeyonSyf } = require('./resolve');
const { copyEntry, generateBuildTime } = require('./copy-entry');

const buildType = process.env.BUILD_TYPE;

if (!isSpecialApp) {
  copyEntry();
}

generateBuildTime();

plugins.push(
  new CleanWebpackPlugin(),
  // new LodashModuleReplacementPlugin(),
  new MiniCssExtractPlugin({
    filename: '[name].[chunkhash:8].css',
    chunkFilename: '[name].[chunkhash:8].chunk.css',
    ignoreOrder: true,
  }),
  new WebpackManifestPlugin({
    generate: (seed, files) => {
      const res = { appId: name };
      files.forEach((file) => {
        // 以index的hash作为判断整个dist离线包是否需要重新下载的flag
        // 生成manifest.json
        if (file.name === 'index.js') {
          if (file.chunk && file.chunk.hash) {
            res.hash = file.chunk.hash;
          }
        }
      });

      return res;
    },
  }),
  new FileManagerPlugin({
    events: {
      onEnd: {
        copy: [{ source: './version.json', destination: './dist/version.json' }],
        delete: ['./version.json'],
      },
    },
  }),
);

if (buildType === 'zip') {
  plugins.push(
    new FileManagerPlugin({
      // 需要在 plugins 数组里添加
      events: {
        onEnd: {
          delete: [
            './dist/hashDist.zip', // 删除之前已经存在的压缩包
          ],
          archive: [{ source: './dist/hashDist', destination: './dist/hashDist.zip' }],
        },
      },
    }),
  );
} else {
  // 非离线应用包启用
  plugins.push(new DynamicPublicPathPlugin());
}

// 分析依赖包
if (process.env.ANALYSE === 'true') {
  plugins.push(new BundleAnalyzerPlugin());
}

let buildConfig = {
  target: ['web', 'es5'],
  mode: 'production',
  entry: {
    index: [resolveApp('src/entry.tsx')],
  },
  output: {
    path: resolveApp(buildType === 'zip' ? 'dist/hashDist/www' : 'dist'),
    filename: '[name].[chunkhash:8].js',
    chunkFilename: '[name].[chunkhash:8].chunk.js',
    // 打包离线包时，相对地
    publicPath: buildType === 'zip' ? './' : `/${name}/`,
  },
  resolve,
  externals,
  plugins,
  performance: {
    hints: false,
  },
  stats: {
    colors: true,
    children: false,
  },
  optimization: {
    chunkIds: 'named',
    minimize: true,
    minimizer: [
      new TerserPlugin({
        // test: /\.js(\?.*)?$/i,
        // parallel: os.cpus().length - 1,
        // exclude: /\/excludes/,
        // include: /\/includes/,
        // minify: TerserPlugin.esbuildMinify,
        // 下面的配置取决于 minify的值，因此下面使用`esbuild` options
        //extractComments: false,
        terserOptions: {
          ecma: 5,
        },
      }),
    ],
    splitChunks: {
      chunks: 'all',
      // maxAsyncRequests: 4,
      // maxInitialRequests:6,
      minSize: 10000,
      minChunks: 3,
      enforceSizeThreshold: 100000,
      cacheGroups: {
        commons: {
          test: /[\\/]node_modules[\\/]/,
          name: 'commons',
          chunks: 'all',
          minChunks: 3,
        },
      },
      // cacheGroups: {
      //   defaultVendors: {
      //     test: /[\\/]node_modules[\\/]/,
      //     filename: '[name].bundle.js',
      //     priority: -10,
      //     reuseExistingChunk: true,
      //   },
      //   default: {
      //     minChunks: 2,
      //     priority: -20,
      //     reuseExistingChunk: true,
      //   },
      // },
    },
  },
  module: {
    rules: [
      {
        test: /\.(js|jsx|ts|tsx)$/,
        // include: [/(src)/, /(node_modules)/],
        include: /(src)/,
        exclude: /(node_modules)/,
        use: [
          {
            loader: 'babel-loader',
            options: {
              cacheDirectory: false,
              // plugins: ['lodash'],
              // ...babelConfigOptions
            },
          },
        ],
      },
      {
        test: /\.(less|css)$/,
        // include: /(src)/,
        // exclude: /(node_modules)/,
        use: [
          {
            loader: MiniCssExtractPlugin.loader,
            options: {
              esModule: true,
            },
          },
          {
            loader: 'css-loader',
            options: {
              modules: {
                auto: true,
                exportLocalsConvention: 'camelCase',
                localIdentName: '[name]-[local]-[hash:5]',
              },
            },
          },
          {
            loader: 'postcss-loader',
            options: {
              postcssOptions: {
                config: resolveSeeyonSyf('scripts/postcss.js'),
              },
            },
          },
          {
            loader: 'less-loader',
            options: {
              lessOptions: {
                javascriptEnabled: true,
              },
            },
          },
        ],
      },
      {
        test: /\.svg$/,
        include: /(src)/,
        exclude: /(node_modules)/,
        use: [
          'babel-loader',
          {
            loader: '@svgr/webpack',
            options: {
              babel: false,
              icon: true,
              titleProp: 'title',
              // ...babelConfigOptions
            },
          },
        ],
      },
      {
        test: /\.(graphql|gql)$/,
        include: /(src)/,
        exclude: /(node_modules)/,
        loader: 'graphql-tag/loader',
      },
      {
        test: /\.(jpg|jpeg|gif|png|eot|ttf|woff|woff2)$/,
        include: /(src)/,
        exclude: /(node_modules)/,
        loader: 'url-loader',
        options: {
          limit: 10000,
          name: '[name].[hash:8].[ext]',
        },
      },
    ],
  },
  cache: {
    type: 'filesystem',
    // 额外的依赖文件，当这些文件内容发生变化时，缓存会完全失效而执行完整的编译构建，通常可设置为项目配置文件
    buildDependencies: {
      defaultWebpack: ['webpack/lib/', '@seeyon/syf/scripts/'],
      config: [__filename],
    },
  },
};

const webpackOverride = getWebpackOverridesConfig();

if (typeof webpackOverride === 'function') {
  let resConfig = webpackOverride(buildConfig, process.env.NODE_ENV);
  if (typeof resConfig === 'object') buildConfig = resConfig;
}

module.exports = buildConfig;
